import { v4 as uuidv4 } from 'uuid';
import {PlatReq} from "../types/CommonTypes";
import {comPlatReq, openLoginModal} from "../ComReq";
import {message} from "antd";

let websocket: WebSocket;
let audioContext: AudioContext;
let scriptProcessor: AudioNode;
let audioInput: MediaStreamAudioSourceNode;
let audioStream: MediaStream;
let msgCallback:(msg: string, msgId?: string) => void;
let msgId: string;
let prevAccessExpireTime: number;
let preAccessInfo: NslAccessInfo;

// 生成 UUID
function generateUUID() {
    return uuidv4().replace(/-/g, '').slice(0, 32);
}
type NslAccessInfo = {
    appkey: string;
    token: string;
    //有效期时间戳，单位秒
    expireTime: number;
}
const initNslToken = ():Promise<NslAccessInfo> => {
    const req: PlatReq ={
        interfaceName: "gainNslToken",
        reqData: {},
    }
    return new Promise((resolve, reject) => {
        comPlatReq(req)
            .then((data)=>{
                const res = data as Record<string, Record<string, string>>;
                const resp:NslAccessInfo = res.result as unknown as NslAccessInfo;
                preAccessInfo = resp;
                resolve(resp);
            })
            .catch((err)=>{reject(err)});
    })
};
// 打开WebSocket连接

const openWs=():Promise<void> => {
    return new Promise((resolve,reject)=>{
        const timestampInSeconds = Math.floor(Date.now() / 1000);
        if (preAccessInfo && prevAccessExpireTime && (prevAccessExpireTime - 10) > timestampInSeconds) {
            //还在有效期里，直接使用
            initWs().then(()=>{
                resolve();
            }).catch(error=>{
                reject(error);
            });
        } else {
            initNslToken().then(()=>{
                initWs().then(()=>{
                    resolve();
                }).catch(error=>{
                    reject(error);
                });
            }).catch(err=>{
                reject(err);
            });
        }
    })
}
const initWs=():Promise<void>=>{
    return new Promise((resolve,reject) => {
        const socketUrl = `wss://nls-gateway.cn-shanghai.aliyuncs.com/ws/v1?token=${preAccessInfo.token}`;
        websocket = new WebSocket(socketUrl);
        websocket.onopen = function() {
            msgId = generateUUID();
            const startTranscriptionMessage = {
                header: {
                    appkey: preAccessInfo.appkey,
                    namespace: "SpeechTranscriber",
                    name: "StartTranscription",
                    task_id: generateUUID(),
                    message_id: msgId
                },
                payload: {
                    "format": "pcm",
                    "sample_rate": 16000,
                    "enable_intermediate_result": true,
                    "enable_punctuation_prediction": true,
                    "enable_inverse_text_normalization": true
                }
            };
            websocket.send(JSON.stringify(startTranscriptionMessage));
            logMessage("链接建立成功")
        };
        websocket.onmessage = function(event) {
            const message = JSON.parse(event.data);
            logMessage(JSON.stringify(message));
            const header = message.header;
            const msgName = header.name;
            if (msgName === "TranscriptionStarted") {
                console.log("websocket 已启动");
                resolve();
            } else if (msgName === "TaskFailed") {
                reject(header.status+ ":" + header.status_text);
            }
            msgCallback(message?.payload?.result, msgId);
        };

        websocket.onerror = function(event) {
            logMessage('WebSocket 错误: ' + event);
        };
        websocket.onclose = function() {
            logMessage('与 WebSocket 服务器断开');
        };
    });
}

// 日志消息
function logMessage(message: string) {
    console.log("logMessage:", message);
}

// 开始录音
export const startRecording=(callback:(msg: string,msgId?:string) => void):Promise<void> => {
    return new Promise((resolve, reject) => {
        if (!msgCallback) {
            msgCallback = callback;
        }
        if (!websocket || websocket.readyState != WebSocket.OPEN) {
            openWs().then(()=>{
                openAudio().then(()=>{
                    resolve();
                }).catch(err=>{
                    reject(err);
                });
            }).catch(err=>{
                if (openLoginModal===err) {
                    message.error("请先登陆");
                } else {
                    message.error(err);
                }
                reject(err);
            });
        } else {
            openAudio().then(()=>{
                resolve();
            }).catch(err=>{
                reject(err);
            });
        }
    })
}
const openAudio=():Promise<void>=> {
    return new Promise((resolve, reject)=>{
        // 获取音频输入设备
        navigator.mediaDevices.getUserMedia({ audio: true }).then(stram=>{
            audioStream = stram;
            audioContext = new window.AudioContext({sampleRate: 16000});
            audioInput = audioContext.createMediaStreamSource(audioStream);

            // 设置缓冲区大小为2048的脚本处理器
            scriptProcessor = audioContext.createScriptProcessor(2048, 1, 1);

            scriptProcessor.onaudioprocess = function(event: { inputBuffer: { getChannelData: (arg0: number) => any; }; }) {
                const inputData = event.inputBuffer.getChannelData(0);
                if (inputData.length<=0) {
                    logMessage("没有监测到语音");
                }
                const inputData16 = new Int16Array(inputData.length);
                for (let i = 0; i < inputData.length; ++i) {
                    inputData16[i] = Math.max(-1, Math.min(1, inputData[i])) * 0x7FFF; // PCM 16-bit
                }
                if (websocket && websocket.readyState === WebSocket.OPEN) {
                    websocket.send(inputData16.buffer);
                    //logMessage('发送音频数据块');
                }
            };
            audioInput.connect(scriptProcessor);
            scriptProcessor.connect(audioContext.destination);
            logMessage("正在监听语音输入");
            resolve();
        }).catch((err)=>{
            reject('录音失败: ' + err);
        });
    });
}

// 停止录音
export const stopRecording=()=> {
    if (scriptProcessor) {
        scriptProcessor.disconnect();
    }
    if (audioInput) {
        audioInput.disconnect();
    }
    if (audioStream) {
        audioStream.getTracks().forEach(track => track.stop());
    }
    if (audioContext) {
        audioContext.close().then(r => {
            console.log("audioContext closed", r);
        });
    }
    if (websocket) {
        websocket.close();
    }
}